#include "stdafx.h"
#include "MCTBusiness.h"

#include "Bios/User.h"
#include "Bus/DataBus.h"
#include "Register/ACC.h"
#include "Register/GPR.h"
#include "Register/VCR.h"


MCTBusiness::MCTBusiness(User& user, MarketSnapshot const& marketSnapshot, VectorRegister& vectorRegister, DealingCache& dealingCache)
	:Business(user),m_marketSnapshot(marketSnapshot),m_vectorRegister(vectorRegister),m_dealingCache(dealingCache)
{
}

MCTBusiness::~MCTBusiness()
{
}

void MCTBusiness::Open(OrderInfo& orderInfo, Exchange::FLAG connectionExch)
{
	orderInfo.businessId = GetId();
	orderInfo.businessPtr = (Business*)(this);

	Dealing dealing(GetUser(), orderInfo);
	m_theOpenDealingCache.Add(m_dealingCache.Save(dealing));

	if (HaveEnoughFunds(orderInfo))
	{
		double freezeFunds = FundsService::FreezeDealingFunds(m_marketSnapshot, m_theOpenDealingCache.Last());
		if (DoubleComparer::equal(freezeFunds, 0))
		{
			Log::Warn(FT("MCTBusiness[%d] Contract[%s] Open() freezeFunds is zero", GetId(), orderInfo.contractCode));
			return;
		}

		ChipMessage message = {0};
		message.type = ChipMessage::ORDER_INSERT;
		memcpy_s(message.data,sizeof(message.data),&m_theOpenDealingCache.Last(),sizeof(Dealing));
		m_vectorRegister.GetExternalQueue(connectionExch).Push(message);
		Log::Info(FT("MCTBusiness[%d] Contract[%s] Open(%d, %d, %.2f) LocalId[%d]", GetId(), orderInfo.contractCode, orderInfo.direction, orderInfo.quantity, orderInfo.price, orderInfo.localId));
	}
}

void MCTBusiness::Offset(OrderInfo& orderInfo, Exchange::FLAG connectionExch)
{
	orderInfo.businessId = GetId();
	orderInfo.businessPtr = (Business*)(this);

	Dealing dealing(GetUser(), orderInfo);
	m_theOffsetDealingCache.Add(m_dealingCache.Save(dealing));
	FundsService::FreezeDealingFunds(m_marketSnapshot, m_theOffsetDealingCache.Last());

	ChipMessage message = {0};
	message.type = ChipMessage::ORDER_INSERT;
	memcpy_s(message.data,sizeof(message.data),&m_theOffsetDealingCache.Last(),sizeof(Dealing));
	m_vectorRegister.GetExternalQueue(connectionExch).Push(message);
	Log::Info(FT("MCTBusiness[%d] Contract[%s] Offset(%d, %d, %.2f) LocalId[%d]", GetId(), orderInfo.contractCode, orderInfo.direction, orderInfo.quantity, orderInfo.price, orderInfo.localId));
}

void MCTBusiness::DoOnInit()
{
	Log::Info(FT("MCTBusiness[%d] is added",GetId()));
}
void MCTBusiness::DoOnMarket(Market const& market)
{
	UNREFERENCED_PARAMETER(market);
}
void MCTBusiness::DoOnPending(PendingItem const& pendingItem)
{
	UNREFERENCED_PARAMETER(pendingItem);
}
void MCTBusiness::DoOnCommand(BusinessCommand const& command)
{
	UNREFERENCED_PARAMETER(command);
}
void MCTBusiness::DoOnTimeout(Timeout const& timeout)
{
	UNREFERENCED_PARAMETER(timeout);
// 	Log::Info(FT("MCTBusiness[%d] Received Timeout Event, Contract[%d] LocalId[%d] TYPE[%d]", GetId(), timeout.GetContractIndex(), timeout.GetLocalId(), timeout.GetType()));
}
void MCTBusiness::DoOnDealing(Dealing const& dealing)
{
	UNREFERENCED_PARAMETER(dealing);
}
void MCTBusiness::DoOnTrade(Trade const& trade)
{
	UNREFERENCED_PARAMETER(trade);
}
void MCTBusiness::DoOnExchangeStatus(int exchangeStatus)
{
	UNREFERENCED_PARAMETER(exchangeStatus);
}

int MCTBusiness::GetActuallyOpenQuantity(OrderInfo const& orderInfo) const
{
	Market const& market = m_marketSnapshot.GetMarket(orderInfo.contractIndex);
	double eachFreezeAmount =market.CalculateTotalFreeze(orderInfo.price, orderInfo.quantity, orderInfo.operation, market.GetVariety().IsMinorContract());
	if (DoubleComparer::less_equal(eachFreezeAmount, 1.00))
	{
		Log::Warn(FT("MCTBusiness[%d] Contract[%s] GetActuallyOpenQuantity() eachFreezeAmount is zero--Unbelievable!", GetId(),market.GetVariety().GetContractCode()));
		eachFreezeAmount = 1.00;
	}

	int canOpenQuantity = (int)(GetUser().GetFunds().GetAvailable()/eachFreezeAmount);
	return min(orderInfo.quantity, canOpenQuantity);
}
bool MCTBusiness::HaveEnoughFunds(OrderInfo const& orderInfo)
{
	if (GetActuallyOpenQuantity(orderInfo) < 1)
	{
		Log::Info(FT("MCTBusiness[%d] Contract[%s] lack of funds", GetId(), orderInfo.contractCode));
		return false;
	}
	return true;
}
